defmodule Strain do
  @doc """
  Given a `list` of items and a function `fun`, return the list of items where
  `fun` returns true.

  Do not use `Enum.filter`.
  """
  @spec keep(list :: list(any), fun :: (any -> boolean)) :: list(any)
  def keep(list, fun) do
    my_kfilter(list, fun)
  end

  defp my_kfilter([], _fun), do: []
  defp my_kfilter([h | t], fun) do
    IO.inspect h
    IO.inspect apply(fun, [h])
    cond do
      apply(fun, [h]) -> [h | my_kfilter(t, fun)]
      # alway call
      true            -> my_kfilter(t, fun)
    end

  end

  @doc """
  Given a `list` of items and a function `fun`, return the list of items where
  `fun` returns false.

  Do not use `Enum.reject`.
  """
  @spec discard(list :: list(any), fun :: (any -> boolean)) :: list(any)
  def discard(list, fun) do
    my_dfilter(list, fun)
  end

  defp my_dfilter([], _fun), do: []
  defp my_dfilter([h | t], fun) do
    #IO.inspect apply(fun, [h])
    cond do
      not apply(fun, [h]) -> [h | my_dfilter(t, fun)]
      true            -> my_dfilter(t, fun)
    end
  end

end
